const errorType = require("../constans/error-types");
const { logger } = require("../../logger");
const Question = require("../model/question.model");
const User = require("../model/user.model");
const Apply = require("../model/apply.model");
const Result = require("../model/result.model");
const QuestionUser = require("../model/question_user.model");
const { Op } = require("sequelize");
const sequelize = require("../app/database");

class QuestionController {
  // 新建评测
  async create(ctx, next) {
    await Question.create(ctx.request.body)
      .then((res) => {
        ctx.success(res);
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  async detail(ctx, next) {
    const { questionId } = ctx.params;
    if (!questionId) {
      const error = new Error(errorType.NOPARAMETER);
      return ctx.app.emit("error", error, ctx);
    }
    await Question.findOne({
      where: { id: questionId },
      raw: true,
    })
      .then((res) => {
        ctx.success(res);
      })
      .catch((err) => {
        ctx.fail(99);
        logger.error(err);
      });
  }

  // 评测列表
  async list(ctx, next) {
    const { limit, offset, keyword } = ctx.query;
    if (!limit || !offset) {
      const error = new Error(errorType.NOPARAMETER);
      return ctx.app.emit("error", error, ctx);
    }
    await Question.findAndCountAll({
      where: {
        title: {
          [Op.like]: `%${keyword}%`,
        },
      },
      include: [
        {
          model: User,
          attributes: ["id", "name", "username"],
        },
      ],
      distinct: true,
      limit: parseInt(limit),
      offset: parseInt(limit) * parseInt(offset - 1),
    })
      .then((res) => {
        ctx.success({
          list: res.rows,
          total: res.count,
          limit,
          offset,
        });
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  // 修改评测
  async update(ctx, next) {
    const { id } = ctx.request.body;
    await Question.update(ctx.request.body, {
      where: {
        id,
      },
    })
      .then((res) => {
        res[0] ? ctx.success() : ctx.fail();
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  async remove(ctx, next) {
    const { questionId } = ctx.params;
    await Question.destroy({
      where: {
        id: questionId,
      },
    })
      .then((res) => {
        res ? ctx.success() : ctx.fail("");
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  // 问卷指定专家
  async questionExpert(ctx, next) {
    await QuestionUser.create(ctx.request.body)
      .then((res) => {
        ctx.success(res);
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  // 自动推荐专家
  async recommendExpert(ctx, next) {
    const { materials_id, question_id, question_round } = ctx.query;
    // 1.找到申请物品对应的标签
    const temp = await Apply.findOne({
      where: { id: materials_id },
    });
    const arr = temp.types.replace(/\[|]/g, "").split(",").map(Number);
    // 2.查找拥有标签的用户id
    let sets = new Set();
    for (let a of arr) {
      await User.findAndCountAll({
        where: {
          expert_type: {
            [Op.like]: `%${a}%`,
          },
          permission: 2,
        },
        order: [["expert_grade", "DESC"]],
        limit: 2,
        offset: 0,
      })
        .then((res) => {
          res.rows.forEach((it) => {
            sets.add(it.id);
          });
        })
        .catch((err) => {
          ctx.fail();
          logger.error(err);  
        });
    }
    // 3.找到的用户数量小于15，就按照专家评分排序
    if (sets.size < 2) {
      await User.findAll({
        where: {
          permission: 2,
        },
        order: [["expert_grade", "DESC"]],
        limit: 10 - sets.size,
        offset: 0,
      })
        .then((res) => {
          res.forEach((it) => {
            if (sets.size < 2) {
              sets.add(it.id);
            }
          });
        })
        .catch((err) => {
          ctx.fail();
          logger.error(err);
        });
    }
    // 3.把专家绑定到问卷上
    for (let value of sets.values()) {
      await QuestionUser.create({
        user_id: value,
        question_id,
        answer_round: question_round,
      })
        .then((res) => {
          ctx.success(res);
        })
        .catch((err) => {
          ctx.fail();
          logger.error(err);
        });
    }
  }

  // 专家回答问卷
  async answerQuestion(ctx, next) {
    const { question_id, user_id, round } = ctx.request.body;
    // 修改问卷
    await QuestionUser.update(ctx.request.body, {
      where: {
        question_id,
        user_id,
        answer_round: round,
      },
    })
      .then((res) => {
        ctx.success();
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
    // 计算平均值
    const size = await QuestionUser.findAll({
      where: {
        question_id,
        answer_round: round,
        max_value: { [Op.gt]: 1 },
      },
    });
    const max = await QuestionUser.sum("max_value", {
      where: { answer_round: round, question_id },
    });
    const possible = await QuestionUser.sum("possible_value", {
      where: { answer_round: round, question_id },
    });
    const min = await QuestionUser.sum("min_value", {
      where: { answer_round: round, question_id },
    });
    const estimate = (max * 0.3 + possible * 0.5 + min * 0.2) / size.length;
    const isResult = await Result.findAll({
      where: {
        answer_id: question_id,
        result_round: round,
      },
    });
    // 没结果就新建
    if (isResult.length > 0) {
      await Result.update(
        {
          estimate,
          result_round: round,
          max_average: max / size.length,
          possible_average: possible / size.length,
          min_average: min / size.length,
          count: sequelize.literal("count+1"),
        },
        {
          where: {
            answer_id: question_id,
            result_round: round,
          },
        }
      );
    } else {
      await Result.create({
        estimate,
        answer_id: question_id,
        result_round: round,
        max_average: max / size.length,
        possible_average: possible / size.length,
        min_average: min / size.length,
      })
        .then((result) => {})
        .catch((err) => {
          console.log(err);
        });
    }
  }

  // 查看计算结果
  async resultList(ctx, next) {
    const { question_id } = ctx.query;
    await Result.findAndCountAll({
      where: {
        answer_id: question_id,
      },
    })
      .then((res) => {
        ctx.success({
          list: res.rows,
        });
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }

  // 查看当前轮次所有回答
  async roundAnswerList(ctx, next) {
    const { round, question_id } = ctx.query;
    await QuestionUser.findAndCountAll({
      where: {
        answer_round: round,
        question_id,
      },
    })
      .then((res) => {
        ctx.success({
          list: res.rows,
        });
      })
      .catch((err) => {
        ctx.fail();
        logger.error(err);
      });
  }
}

module.exports = new QuestionController();
